package bancosys.tec.datadigester.processor;

import jmine.tec.datadigester.DataDigesterMessages;
import jmine.tec.executionlog.ExecutionLogController;
import jmine.tec.executionlog.domain.enumx.ExecutionItemStatus;
import bancosys.tec.datadigester.DataDigesterException;
import bancosys.tec.datadigester.DigesterBean;
import bancosys.tec.datadigester.DigesterItemBean;
import bancosys.tec.persist.traverse.BeanTraverser;
import bancosys.tec.utils.traverser.TraverseException;

import com.thoughtworks.xstream.XStream;

/**
 * Classe auxiliar para as implementações de Processor.
 * 
 * @author Marco, piercio
 */
public abstract class AbstractProcessor implements Processor {

    private BeanTraverser beanTraverser;

    private ExecutionLogController executionLogController;

    /**
     * Define o valor para o campo beanTraverser.
     * 
     * @param beanTraverser o valor para o campo beanTraverser.
     */
    public void setBeanTraverser(BeanTraverser beanTraverser) {
        this.beanTraverser = beanTraverser;
    }

    /**
     * @param executionLogController o valor para o campo executionLogController
     */
    public void setExecutionLogController(ExecutionLogController executionLogController) {
        this.executionLogController = executionLogController;
    }

    /**
     * Deve ser implementado nos filhos.
     * 
     * @param bean processa bean.
     */
    protected abstract void doProcess(DigesterBean bean);

    /**
     * Forca todos campos de strings do bean (e filhos) para upperCase.
     * 
     * @param bean bean.
     */
    private void traverse(DigesterBean bean) {
        try {
            this.beanTraverser.traverse(bean);
        } catch (TraverseException e) {
            throw new DataDigesterException(DataDigesterMessages.BEAN_TRAVERSER_FAILURE.create(), e);
        }
    }

    /**
     * Processa bean de data digester.
     * 
     * @param bean processa bean.
     */
    public final void process(DigesterBean bean) {
        if (this.beanTraverser != null) {
            this.traverse(bean);
        }
        this.doProcess(bean);
    }

    /**
     * Adiciona uma mensagem de inserção de item no log de execução.
     * 
     * @param message a mensagem.
     * @param beanXml o item em formato xml.
     */
    protected void addExecutionLogInsertItem(String message, DigesterItemBean beanXml) {
        this.executionLogController.addLogItem(this.toXml(beanXml), message, ExecutionItemStatus.INSERT);
    }

    /**
     * Adiciona uma mensagem de alteração de item no log de execução.
     * 
     * @param message a mensagem.
     * @param beanXml o item em formato xml.
     */
    protected void addExecutionLogUpdateItem(String message, DigesterItemBean beanXml) {
        this.executionLogController.addLogItem(this.toXml(beanXml), message, ExecutionItemStatus.UPDATE);
    }

    /**
     * Adiciona uma mensagem de alerta que item tem pendencias no log de execução.
     * 
     * @param message a mensagem.
     * @param beanXml o item em formato xml.
     */
    protected void addExecutionLogAlertItem(String message, DigesterItemBean beanXml) {
        this.executionLogController.addLogItem(this.toXml(beanXml), message, ExecutionItemStatus.ALERT);
    }

    /**
     * Adiciona uma mensagem de que item foi ignorado no log de execução.
     * 
     * @param message a mensagem.
     * @param beanXml o item em formato xml.
     */
    protected void addExecutionLogIgnoreItem(String message, DigesterItemBean beanXml) {
        this.executionLogController.addLogItem(this.toXml(beanXml), message, ExecutionItemStatus.IGNORE);
    }

    /**
     * Adiciona uma mensagem de erro de item no log de execução.
     * 
     * @param message a mensagem.
     * @param beanXml o item em formato xml.
     * @param e a exceção lançada pelo erro.
     */
    protected void addExecutionLogErrorItem(String message, DigesterItemBean beanXml, Exception e) {
        this.executionLogController.addErrorItem(this.toXml(beanXml), message, e);
    }

    /**
     * Serializa o bean passado em xml.
     * 
     * @param bean o bean que será serializado.
     * @return o xml que representa esse bean.
     */
    private String toXml(DigesterItemBean bean) {
        XStream xstream = new XStream();
        xstream.autodetectAnnotations(true);
        return "<bean>" + xstream.toXML(bean) + "</bean>";
    }

}
